﻿using System.Collections.Generic;
using Generator.Selections.DataDictionary;
using Microsoft.VisualStudio.Modeling.Diagrams;
using System.Linq;

namespace Manor.CslaDesigner.DslPackage.CustomCode
{
    class ModelClassManager
    {
        private readonly List<ModelClass> _newModelClasses;
        private readonly ModelRoot _modelRoot;
        private readonly List<Table> _tableList;
        private readonly string _nameSpace;

        public ModelClassManager(ModelRoot modelRoot, List<Table> tableList, string nameSpace)
        {
            _newModelClasses = new List<ModelClass>();
            _modelRoot = modelRoot;
            _tableList = tableList;
            _nameSpace = nameSpace;
        }

        public void AddModelClassesWithAssociations()
        {
            using (var transaction = _modelRoot.Store.TransactionManager.BeginTransaction("update model"))
            {
                AddModelClasses();
                GenerateAssociations(_modelRoot, _tableList);

                transaction.Commit();
            }
        }

        public void AdjustNewModelClassPosition()
        {
            if (_newModelClasses.Count > 0)
            {
                using (var transaction = _modelRoot.Store.TransactionManager.BeginTransaction("update model"))
                {
                    double ? lastXPos = null, lastYPos = null;
                    foreach (var classShape in _newModelClasses.Select(
                        newModeClass => PresentationViewsSubject.GetPresentation(newModeClass).FirstOrDefault()).OfType<ClassShape>())
                    {
                        if (lastXPos.HasValue)
                            lastXPos += 3.0;
                        else
                            lastXPos = classShape.Location.X;

                        if (lastYPos.HasValue)
                            lastYPos += 0.5;
                        else
                            lastYPos = classShape.Location.Y;

                        classShape.Location = new PointD(lastXPos.Value, lastYPos.Value);
                    }
                    transaction.Commit();
                }

                _newModelClasses.Clear();
            }
        }

        private void AddModelClasses()
        {
            foreach (var table in _tableList)
            {
                var mc = AddModelClass(_modelRoot, table, _nameSpace);

                AddAttributesFromColumns(table, mc);
                mc.ModelRoot = _modelRoot;
                _newModelClasses.Add(mc);
            }
        }

        private  ModelClass AddModelClass(ModelRoot mr, Table table, string nameSpace)
        {
            var modelClass = new ModelClass(mr.Partition)
            {
                Name = table.ClassName,
                EditableBusinessObject = table.EditableBusinessObject,
                DerivedFromTable = table.TableName,
                NameSpace= nameSpace                
            };          

            return modelClass;
        }

        private  void AddAttributesFromColumns(Table table, ModelClass modelClass)
        {
            foreach (var column in table.ColumnList)
            {
                if (!column.Selected) continue;

                var modelAttribute = CreateModelAttribute(modelClass, column);
                modelClass.Attributes.Add(modelAttribute);
            }
        }

        private  ModelAttribute CreateModelAttribute(ModelClass modelClass, Column column)
        {
            var modelAttribute = new ModelAttribute(modelClass.Partition, null)
                {
                    Name = column.AttributeName,
                    Type = column.DataType,
                    Required = column.Mandatory,
                    DerivedFromColumn = column.ColumnName,
                    GenerateCslaProperty = true,
                    PrimaryKey= column.PrimaryKey
                }
                ;

            if (column.MaxLen.HasValue)
                modelAttribute.MaximalLength = column.MaxLen.Value;

            return modelAttribute;
        }

        private  void GenerateAssociations(ModelRoot mr, IEnumerable<Table> tableList)
        {
            foreach (var table in tableList)
            {
                foreach (var relation in table.RelationList)
                {
                    ModelClass from = null;
                    ModelClass to = null;
                    foreach (var type in mr.Types)
                    {
                        var mc = type as ModelClass;
                        if (mc != null)
                        {
                            if (mc.DerivedFromTable == table.TableName)
                                to = mc;
                            else if (mc.DerivedFromTable == relation.ToTableName)
                                from = mc;
                        }
                    }

                    if (from != null && to != null)
                    {
// ReSharper disable ObjectCreationAsStatement
                        new UnidirectionalAssociation(from, to)
// ReSharper restore ObjectCreationAsStatement
                            {
                                SourceRoleName = string.Format("Has{0}", to.Name),
                                SourceMultiplicity = Multiplicity.One,
                                TargetMultiplicity = Multiplicity.ZeroMany
                            };
                    }
                }
            }
        }

    }
}